package de.syfy.project.engine;

import de.syfy.project.engine.utils.Vector2D;
import de.syfy.project.engine.interfaces.World;
import de.syfy.project.engine.errors.NoSuchAnimationException;
import java.util.HashMap;
import java.util.Map;
import de.syfy.project.engine.interfaces.Game;
import de.syfy.project.engine.interfaces.Drawable;
import de.syfy.project.engine.interfaces.Movable;
import de.syfy.project.engine.interfaces.SpriteEvent;
import de.syfy.project.engine.interfaces.SpriteAnimation;
import de.syfy.project.game.GamePanel;
import java.awt.geom.Point2D;
import static org.lwjgl.opengl.GL11.*;

/**
 *
 * @author Timo
 */
public abstract class Sprite implements Drawable,Movable,SpriteAnimation,SpriteEvent{
    public static long DELAY = 200;
    Map<String,Animation> animationMap;
    Animation currentAnimation;
    Texture actualTexture;
    long animation = 0;
    float width;
    float height;
    float x,y;
    Game game;
    World acutalWorld;
    
    public Sprite(Game game){
        this.game = game;
        this.animationMap = new HashMap<String, Animation>();
        GamePanel gp = (GamePanel) game;
        acutalWorld = gp.getActualWorld();
        
    }
    
    
    public float getWidth(){
        return width;
    }
    
    public float getHeight(){
        return height;
    }
    /**
     * Methode wird zum Animieren des Sprites genutzt. Setzt das nächste Bild
     * zum Animieren.
     */
    public void setNext(){
        actualTexture = currentAnimation.getNext();
    }
    
    /**
     * Registriert eine SpriteAnimation bestehend aus mehreren Texturen.
     * 
     * @param name
     * @param ani 
     */
    @Override
    public void registerAnimation(String name, Animation ani){
        animationMap.put(name, ani);
        if(actualTexture == null){
            currentAnimation = ani;
        }
    }
    
    /**
     * Spielt eine SpriteAnimation mit gegebenen Namen ab, wenn vorhanden.
     * 
     * @param name
     * @throws NoSuchAnimationException 
     */
    @Override
    public void playAnimation(String name) throws NoSuchAnimationException{
        if(!animationMap.containsKey(name)){
            throw new NoSuchAnimationException("Es wurde keine Animation mit "
                    + "dem Namen '"+name+"' registriert.");
        }
        currentAnimation = animationMap.get(name);
    }
    
    /**
     * Wird standardmäßig zum Berrechnen von Animationen genutzt. (Folgendes Bild).
     * Wenn doLogic überschrieben werden soll zunächst einen super-call machen.
     * 
     * @param delta Zeit, die für das Zeichnen des letzten Frames benötigt wurde.
     */
    @Override
    public void doLogic(long delta){
        animation += delta;
        if(animation >= currentAnimation.getTiming()){
            setNext();
            currentAnimation.setNextTiming();
            animation = 0;
        }
    }
    
    @Override
    public void move(Vector2D v){
        this.x += v.getX();
        this.y += v.getY();
    }
    
    
    @Override
    public void drawObject(){ 
        Point2D.Float p = game.worldPointToUIPoint(getPosition());
        glEnable(GL_TEXTURE_2D);
        glPushMatrix();    
        actualTexture.bind();
        glTranslatef(p.x, p.y, 0);
        glBegin(GL_QUADS);
            glColor3f(255f,255f,255f);
            glTexCoord2f(0, 0);
            glVertex2f(0, 0);
            glTexCoord2f(0, actualTexture.getHeight());
            glVertex2f(0, actualTexture.getImageHeight());
            glTexCoord2f(actualTexture.getWidth(), actualTexture.getHeight());
            glVertex2f(actualTexture.getImageWidth(), actualTexture.getImageHeight());
            glTexCoord2f(actualTexture.getWidth(), 0);
            glVertex2f(actualTexture.getImageWidth(), 0);
        glEnd();
        glPopMatrix();       
        glDisable(GL_TEXTURE_2D);
    }
}
